#include "MarketEngine.h"
#include "ThostFtdcMdApi.h"
#include <QDebug>
#include <QDir>
#include <QLibrary>
#include <spdlog/spdlog.h>
#include <QTextCodec>
#include <mutex>
#include <algorithm>


namespace MarketEngine {

class Engine::EnginePrivate : public CThostFtdcMdSpi
{
public:
    explicit EnginePrivate(Engine* q) : q_ptr(q) {}
    ~EnginePrivate() { cleanup(); }

    // 初始化
    bool init(const MarketConfig& config, std::shared_ptr<spdlog::logger> logger);
    void cleanup();
    
    // 公开 mdApi 访问
    CThostFtdcMdApi* getMdApi() const { return mdApi; }
    void setMdApi(CThostFtdcMdApi* api) { mdApi = api; }
    
    // CTP回调实现
    void OnFrontConnected() override;
    void OnFrontDisconnected(int nReason) override;
    void OnRspUserLogin(CThostFtdcRspUserLoginField *pRspUserLogin,
                       CThostFtdcRspInfoField *pRspInfo, 
                       int nRequestID, 
                       bool bIsLast) override;
    void OnRspSubMarketData(CThostFtdcSpecificInstrumentField *pSpecificInstrument,
                           CThostFtdcRspInfoField *pRspInfo,
                           int nRequestID,
                           bool bIsLast) override;
    void OnRspUnSubMarketData(CThostFtdcSpecificInstrumentField *pSpecificInstrument,
                             CThostFtdcRspInfoField *pRspInfo,
                             int nRequestID,
                             bool bIsLast) override;
    void OnRtnDepthMarketData(CThostFtdcDepthMarketDataField *pDepthMarketData) override;
    void OnRspError(CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast) override;

    // 添加订阅方法到 EnginePrivate
    bool subscribe(const std::vector<QString>& symbols);

    // 在 Engine::EnginePrivate 类中添加辅助函数
    QString gbkToUtf8(const char* gbkStr);

private:
    Engine* q_ptr;
    CThostFtdcMdApi* mdApi{nullptr};
    MarketConfig config;
    int requestID{0};
    std::vector<QString> subscribedSymbols;  // 已订阅的合约列表
    std::mutex symbolsMutex;                 // 保护订阅列表的互斥锁
    std::shared_ptr<spdlog::logger> logger;  // 添加 logger 成员
    
    // 辅助函数
    bool isError(CThostFtdcRspInfoField *pRspInfo);
    friend class Engine;  // 允许 Engine 访问私有成员
};

Engine::Engine(QObject* parent) 
    : QObject(parent)
    , d_ptr(new EnginePrivate(this))
{
    static bool registered = false;
    if (!registered) {
        qRegisterMetaType<ConnectionStatus>("ConnectionStatus");
        qRegisterMetaType<CThostFtdcDepthMarketDataField>("CThostFtdcDepthMarketDataField");
        registered = true;
    }
}

Engine::~Engine() = default;

bool Engine::init(const MarketConfig& config, std::shared_ptr<spdlog::logger> externalLogger)
{
    try {
        // 如果传入了外部 logger，使用它；否则创建默认 logger
        if (externalLogger) {
            logger = externalLogger;
        } else {
            // 创建默认 logger
            logger = spdlog::stdout_color_mt("market_engine");
        }
        
        logger->info("Initializing market engine...");
        
        return d_ptr->init(config, logger);
    } catch (const std::exception& e) {
        if (logger) {
            logger->error("Initialization failed: {}", e.what());
        }
        return false;
    }
}

void Engine::start()
{
    try {
        if (d_ptr->getMdApi()) {
            status = ConnectionStatus::Connecting;
            emit onStatusChanged(status);
            d_ptr->getMdApi()->Init();
        }
    } catch (const std::exception& e) {
        status = ConnectionStatus::Disconnected;
        emit onStatusChanged(status);
        emit onError(-1, QString("Connection failed: %1").arg(e.what()));
        if (logger) {
            logger->error("Connection failed: {}", e.what());
        }
    }
}

void Engine::stop()
{
    try {
        if (d_ptr->getMdApi()) {
            status = ConnectionStatus::Disconnecting;
            emit onStatusChanged(status);
            d_ptr->getMdApi()->Release();
            d_ptr->setMdApi(nullptr);
        }
        status = ConnectionStatus::Disconnected;
        emit onStatusChanged(status);
    } catch (const std::exception& e) {
        status = ConnectionStatus::Disconnected;
        emit onStatusChanged(status);
        emit onError(-1, QString("Disconnection failed: %1").arg(e.what()));
        if (logger) {
            logger->error("Disconnection failed: {}", e.what());
        }
    }
}

bool Engine::subscribe(const std::vector<QString>& symbols)
{
    if (symbols.empty() || !d_ptr->getMdApi()) {
        return false;
    }
    
    std::vector<char*> instrumentIDs;
    instrumentIDs.reserve(symbols.size());
    
    for (const auto& symbol : symbols) {
        QByteArray ba = symbol.toLocal8Bit();
        char* id = new char[ba.size() + 1];
        strcpy(id, ba.constData());
        instrumentIDs.push_back(id);
    }
    
    int result = d_ptr->getMdApi()->SubscribeMarketData(instrumentIDs.data(), instrumentIDs.size());
    
    // 清理内存
    for (auto id : instrumentIDs) {
        delete[] id;
    }
    
    return result == 0;
}

bool Engine::unsubscribe(const std::vector<QString>& symbols)
{
    if (symbols.empty() || !d_ptr->getMdApi()) {
        return false;
    }
    
    std::vector<char*> instrumentIDs;
    instrumentIDs.reserve(symbols.size());
    
    for (const auto& symbol : symbols) {
        QByteArray ba = symbol.toLocal8Bit();
        char* id = new char[ba.size() + 1];
        strcpy(id, ba.constData());
        instrumentIDs.push_back(id);
    }
    
    int result = d_ptr->getMdApi()->UnSubscribeMarketData(instrumentIDs.data(), instrumentIDs.size());
    
    // 清理内存
    for (auto id : instrumentIDs) {
        delete[] id;
    }
    
    return result == 0;
}

bool Engine::EnginePrivate::init(const MarketConfig& cfg, std::shared_ptr<spdlog::logger> log)
{
    config = cfg;
    logger = log;  // 保存 logger
    
    if (!config.mdDllPath.isEmpty()) {
        QLibrary lib(config.mdDllPath);
        if (!lib.load()) {
            if (this->logger) {
                this->logger->error("Failed to load CTP library: {}", lib.errorString().toStdString());
            }
            emit q_ptr->onError(-1, QString("Failed to load CTP library: %1").arg(lib.errorString()));
            return false;
        }
        
        // 获取创建函数 - 根据平台使用不同的导出名
        CreateFtdcMdApiFunc createApi = nullptr;
        
#if defined(Q_OS_WIN)
    #if defined(Q_PROCESSOR_X86_64)
        createApi = (CreateFtdcMdApiFunc)lib.resolve("?CreateFtdcMdApi@CThostFtdcMdApi@@SAPEAV1@PEBD_N1@Z");
    #else
        createApi = (CreateFtdcMdApiFunc)lib.resolve("?CreateFtdcMdApi@CThostFtdcMdApi@@SAPAV1@PBD_N1@Z");
    #endif
#else
        createApi = (CreateFtdcMdApiFunc)lib.resolve("_ZN15CThostFtdcMdApi15CreateFtdcMdApiEPKcbb");
#endif

        if (!createApi) {
            if (this->logger) {
                this->logger->error("Failed to resolve CreateFtdcMdApi: {}", lib.errorString().toStdString());
            }
            emit q_ptr->onError(-1, QString("Failed to resolve CreateFtdcMdApi: %1").arg(lib.errorString()));
            return false;
        }
        
        // 检查并创建流文件目录
        QDir dir;
        if (!dir.exists(config.flowPath)) {
            if (!dir.mkpath(config.flowPath)) {
                if (this->logger) {
                    this->logger->error("Failed to create flow path: {}", config.flowPath.toStdString());
                }
                emit q_ptr->onError(-1, QString("Failed to create flow path: %1").arg(config.flowPath));
                return false;
            }
            if (this->logger) {
                this->logger->info("Created flow path: {}", config.flowPath.toStdString());
            }
        }
        
        // 建API实例
        mdApi = createApi(
            config.flowPath.toLocal8Bit().constData(),
            config.connection.enableUdp,
            false  // multicast
        );
        
        if (!mdApi) {
            if (this->logger) {
                this->logger->error("Failed to create CTP MD API instance");
            }
            emit q_ptr->onError(-1, "Failed to create CTP MD API instance");
            return false;
        }
        
        mdApi->RegisterSpi(this);
        mdApi->RegisterFront(const_cast<char*>(config.frontAddress.toLocal8Bit().constData()));
        
        return true;
    }
    
    if (logger) {
        logger->error("MD library path is not specified");
    }
    emit q_ptr->onError(-1, "MD library path is not specified");
    return false;
}

void Engine::EnginePrivate::cleanup()
{
    {
        std::lock_guard<std::mutex> lock(symbolsMutex);
        subscribedSymbols.clear();
    }
    
    if (mdApi) {
        mdApi->Release();
        mdApi = nullptr;
    }
}

void Engine::EnginePrivate::OnFrontConnected()
{
    try {
        if (!mdApi) {
            if (this->logger) {
                this->logger->error("MdApi is null in OnFrontConnected");
            }
            return;
        }

        q_ptr->status = ConnectionStatus::Connected;
        emit q_ptr->onStatusChanged(q_ptr->status);
        
        // 执行登录
        CThostFtdcReqUserLoginField loginField{};
        strncpy(loginField.BrokerID, config.brokerID.toLocal8Bit().constData(), sizeof(loginField.BrokerID) - 1);
        strncpy(loginField.UserID, config.userID.toLocal8Bit().constData(), sizeof(loginField.UserID) - 1);
        strncpy(loginField.Password, config.password.toLocal8Bit().constData(), sizeof(loginField.Password) - 1);
        
        int result = mdApi->ReqUserLogin(&loginField, ++requestID);
        if (result != 0) {
            if (this->logger) {
                this->logger->error("Failed to send login request, error code: {}", result);
            }
            emit q_ptr->onError(result, "Failed to send login request");
            return;
        }
        if (this->logger) {
            this->logger->info("Login request sent successfully");
        }
    } catch (const std::exception& e) {
        if (this->logger) {
            this->logger->error("Exception in OnFrontConnected: {}", e.what());
        }
        emit q_ptr->onError(-1, QString("Exception in OnFrontConnected: %1").arg(e.what()));
    } catch (...) {
        if (this->logger) {
            this->logger->error("Unknown exception in OnFrontConnected");
        }
        emit q_ptr->onError(-1, "Unknown exception in OnFrontConnected");
    }
}

bool Engine::EnginePrivate::isError(CThostFtdcRspInfoField *pRspInfo)
{
    return pRspInfo && pRspInfo->ErrorID != 0;
}

void Engine::EnginePrivate::OnFrontDisconnected(int nReason)
{
    if (this->logger) {
        this->logger->warn("Front disconnected, reason: {}", nReason);
    }
    q_ptr->status = ConnectionStatus::Disconnected;
    emit q_ptr->onStatusChanged(q_ptr->status);
    
    QString errorMsg;
    switch (nReason) {
        case 0x1001: errorMsg = "Network read failed"; break;
        case 0x1002: errorMsg = "Network write failed"; break;
        case 0x2001: errorMsg = "Heartbeat timeout"; break;
        case 0x2002: errorMsg = "Failed to send heartbeat"; break;
        case 0x2003: errorMsg = "Received error message"; break;
        default: errorMsg = QString("Unknown error %1").arg(nReason);
    }
    
    emit q_ptr->onError(nReason, errorMsg);
}

void Engine::EnginePrivate::OnRspUserLogin(CThostFtdcRspUserLoginField *pRspUserLogin, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
    if (pRspInfo && pRspInfo->ErrorID != 0) {
        if (this->logger) {
            this->logger->error("Login failed: [{}] {}", pRspInfo->ErrorID, pRspInfo->ErrorMsg);
        }
        q_ptr->status = ConnectionStatus::Disconnected;
        emit q_ptr->onStatusChanged(q_ptr->status);
        emit q_ptr->onError(pRspInfo->ErrorID, QString::fromLocal8Bit(pRspInfo->ErrorMsg));
        return;
    }
    
    if (pRspUserLogin) {
        if (this->logger) {
            this->logger->info("Login successful. Trading day: {}, Login time: {}, Broker: {}, Front: {}",
                pRspUserLogin->TradingDay,
                pRspUserLogin->LoginTime,
                pRspUserLogin->BrokerID,
                pRspUserLogin->FrontID
            );
        }
        
        q_ptr->status = ConnectionStatus::Connected;
        emit q_ptr->onStatusChanged(q_ptr->status);
    }
}

void Engine::EnginePrivate::OnRspError(CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
    if (pRspInfo && pRspInfo->ErrorID != 0) {
        if (this->logger) {
            this->logger->error("Error: [{}] {}", pRspInfo->ErrorID, pRspInfo->ErrorMsg);
        }
        emit q_ptr->onError(pRspInfo->ErrorID, QString::fromLocal8Bit(pRspInfo->ErrorMsg));
    }
}

void Engine::EnginePrivate::OnRspSubMarketData(CThostFtdcSpecificInstrumentField *pSpecificInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast)
{
    if (pRspInfo && pRspInfo->ErrorID != 0) {
        QString errorMsg = gbkToUtf8(pRspInfo->ErrorMsg);
        if (this->logger) {
            this->logger->error("Subscribe failed: {}", errorMsg.toStdString());
        }
        emit q_ptr->onError(pRspInfo->ErrorID, errorMsg);
        return;
    }
    
    if (pSpecificInstrument) {
        std::lock_guard<std::mutex> lock(symbolsMutex);
        QString instrumentID = gbkToUtf8(pSpecificInstrument->InstrumentID);
        subscribedSymbols.push_back(instrumentID);
        if (this->logger) {
            this->logger->info("Subscribed: {}", instrumentID.toStdString());
        }
    }
}

void Engine::EnginePrivate::OnRspUnSubMarketData(CThostFtdcSpecificInstrumentField *pSpecificInstrument,
                                               CThostFtdcRspInfoField *pRspInfo,
                                               int nRequestID,
                                               bool bIsLast)
{
    if (isError(pRspInfo)) {
        QString errorMsg = gbkToUtf8(pRspInfo->ErrorMsg);
        emit q_ptr->onError(pRspInfo->ErrorID, errorMsg);
        return;
    }

    if (pSpecificInstrument) {
        QString instrumentID = gbkToUtf8(pSpecificInstrument->InstrumentID);
        
        // 从已订阅列表中移除
        {
            std::lock_guard<std::mutex> lock(symbolsMutex);
            auto it = std::find(subscribedSymbols.begin(), subscribedSymbols.end(), instrumentID);
            if (it != subscribedSymbols.end()) {
                subscribedSymbols.erase(it);
            }
        }
        
        if (this->logger) {
            this->logger->trace("Successfully unsubscribed from: {}", instrumentID.toStdString());
        }
    }
}

void Engine::EnginePrivate::OnRtnDepthMarketData(CThostFtdcDepthMarketDataField *pDepthMarketData)
{
    if (pDepthMarketData) {
        // 转换合约代码为 UTF-8
        pDepthMarketData->InstrumentID[sizeof(pDepthMarketData->InstrumentID) - 1] = '\0';
        QString instrumentID = gbkToUtf8(pDepthMarketData->InstrumentID);
        if (this->logger) {
            this->logger->trace("Received tick for: {} @ {}", 
                         instrumentID.toStdString(), 
                         pDepthMarketData->LastPrice);
        }
        emit q_ptr->onTick(*pDepthMarketData);
    }
}

bool Engine::EnginePrivate::subscribe(const std::vector<QString>& symbols)
{
    if (symbols.empty() || !mdApi) {
        return false;
    }
    
    std::vector<char*> instrumentIDs;
    instrumentIDs.reserve(symbols.size());
    
    for (const auto& symbol : symbols) {
        QByteArray ba = symbol.toLocal8Bit();
        char* id = new char[ba.size() + 1];
        strcpy(id, ba.constData());
        instrumentIDs.push_back(id);
    }
    
    int result = mdApi->SubscribeMarketData(instrumentIDs.data(), instrumentIDs.size());
    
    // 清理内存
    for (auto id : instrumentIDs) {
        delete[] id;
    }
    
    return result == 0;
}

QString Engine::EnginePrivate::gbkToUtf8(const char* gbkStr) {
    QByteArray gbkData(gbkStr);
    QTextCodec *gbk = QTextCodec::codecForName("GBK");
    if (!gbk) {
        return QString::fromLocal8Bit(gbkStr);
    }
    return gbk->toUnicode(gbkData);
}

std::vector<QString> Engine::getSubscribedSymbols() const
{
    std::lock_guard<std::mutex> lock(d_ptr->symbolsMutex);
    return d_ptr->subscribedSymbols;
}

} // namespace MarketEngine 